﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace SharedGenomics.Core
{
    public class CommandLineParser
    {
        public CommandLineParser(IEnumerable<string> commandLine)
        {
            this.Switches = new Dictionary<string, string>();
            this.ArgumentList = new List<string>();
            this.ParseCommandLine(commandLine ?? Enumerable.Empty<string>());
        }

        public string GetArgumentForSwitch(string @switch)
        {
            @switch.ThrowIfNull("@switch");
            ExceptionHelper.ThrowIf<ArgumentException>(!this.SwitchExists(@switch), String.Format("Switch {0} not found", @switch));

            return this.Switches[@switch];
        }

        public bool TryGetSwitch(string @switch, out string arg)
        {
            if (@switch == null)
            {
                arg = null;
                return false;
            }
            else
            {
                return this.Switches.TryGetValue(@switch, out arg);
            }
        }

        public bool SwitchExists(string @switch)
        {
            return @switch != null && this.Switches.ContainsKey(@switch);
        }

        public IEnumerable<string> Arguments
        {
            get { return this.ArgumentList; }
        }

        private void ParseCommandLine(IEnumerable<string> commandLine)
        {
            Debug.Assert(commandLine != null);
            string lastValue = null;

            commandLine.Aggregate((string)null, (prev, curr) =>
            {
                lastValue = curr;
                if (this.IsSwitch(prev))
                {
                    //if current value is a switch, then the previous value was a switch with no arguments, otherwise current is the argument
                    this.AddSwitch(prev, this.IsSwitch(curr) ? null : curr);
                }
                else if (!this.IsSwitch(curr))
                {
                    //previous value was not a switch - since current is not a switch it is an argument
                    this.ArgumentList.Add(curr);
                }

                return curr;
            });

            //check to see if last argument was a switch - if so it will not have been added
            if (this.IsSwitch(lastValue))
                this.AddSwitch(lastValue, null);
        }

        private bool IsSwitch(string str)
        {
            return str != null &&
                    (str.StartsWith("-") || str.StartsWith("/"));
        }

        private void AddSwitch(string @switch, string value)
        {
            Debug.Assert(this.IsSwitch(@switch));

            //strip leading / or - from switch and associate with value
            this.Switches.Add(@switch.Substring(1), value);
        }

        private IList<string> ArgumentList { get; set; }
        private IDictionary<string, string> Switches { get; set; }
    }
}
